﻿<?xml version="1.0" encoding="utf-8"?><Articles><Article><ArticlesID>862</ArticlesID><Title>ADO.NET 2.0 (phần 1)</Title><Body>&amp;lt;p&amp;gt;ADO.NET 2.0 class library d&amp;amp;ugrave;ng để truy  cập dữ liệu m&amp;amp;agrave; .NET Framework 2.0 cung cấp. Nếu sử dụng tốt ADO.NET 2.0  (v&amp;amp;agrave; Visual Studio 2005) th&amp;amp;igrave; c&amp;amp;oacute; thể giảm đ&amp;amp;aacute;ng kể chi ph&amp;amp;iacute; cần thiết cho  việc tạo Business Entity v&amp;amp;agrave; Data Access Logic Component. (Trong t&amp;amp;agrave;i liệu  n&amp;amp;agrave;y cũng giải th&amp;amp;iacute;ch một c&amp;amp;aacute;ch đơn giản về 2 thuật ngữ Business Entity v&amp;amp;agrave;  Data Access Logic Component. Về chi tiết xin tham khảo địa chỉ sau  Application Architecture for .NET). ...&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;a href=&amp;quot;http://dev.meotom.net/2010/3/24/ADO-NET-2-0-phan-2-35F.htm&amp;quot;&amp;gt;&amp;amp;gt;&amp;amp;gt;ADO.NET 2.0 (phần 2)&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Điều quan trọng khi tạo Business Entity l&amp;amp;agrave; sử dụng  Visual Studio 2005 để tạo Typed-DataSet, tạo cấu tr&amp;amp;uacute;c Class giống với cấu tr&amp;amp;uacute;c Table của RDBMS (Relational Database Management System). Nếu sử dụng nguy&amp;amp;ecirc;n DataSet class của System Data Namespace thấy trong s&amp;amp;aacute;ch vở, th&amp;amp;igrave; kh&amp;amp;ocirc;ng thể thỏa m&amp;amp;atilde;n được y&amp;amp;ecirc;u cầu về business application.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Điều quan trọng khi tạo Data Access Logic Component l&amp;amp;agrave; sử dụng Visual Studio 2005, để tạo tự động TableAdapter. Nếu TableAdapter được sinh tự động bằng Visual Studio 2005 th&amp;amp;igrave; source code mở kết nối dữ liệu, tạo c&amp;amp;acirc;u lệnh SQL sẽ tự động được sinh ra cho n&amp;amp;ecirc;n sẽ giảm được c&amp;amp;ocirc;ng sức. Hơn hết, c&amp;amp;oacute; thể tr&amp;amp;aacute;nh được việc Logic để truy cập data được viết trong presentation như Windows Forms v&amp;amp;agrave; ASP.NET, v&amp;amp;agrave; khi ph&amp;amp;aacute;t sinh tr&amp;amp;ugrave;ng sẽ kh&amp;amp;ocirc;ng thể bảo tr&amp;amp;igrave;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Sau đ&amp;amp;acirc;y ch&amp;amp;uacute;ng t&amp;amp;ocirc;i xin m&amp;amp;ocirc; tả chi tiết hơn về những vấn đề n&amp;amp;agrave;y.&amp;lt;/p&amp;gt;
&amp;lt;h2&amp;gt;C&amp;amp;aacute;ch  tạo Business Entity&amp;lt;/h2&amp;gt;
&amp;lt;p&amp;gt;Business Entity l&amp;amp;agrave; class hiển thị Data được  xử l&amp;amp;yacute; trong business application. Tất cả business application, kh&amp;amp;ocirc;ng c&amp;amp;oacute; ngoại lệ, sẽ xử l&amp;amp;iacute; data. V&amp;amp;iacute; dụ như trong ph&amp;amp;acirc;n phối sản phẩm th&amp;amp;igrave; n&amp;amp;oacute; l&amp;amp;agrave; th&amp;amp;ocirc;ng tin sản phẩm, th&amp;amp;ocirc;ng tin kh&amp;amp;aacute;ch h&amp;amp;agrave;ng, th&amp;amp;ocirc;ng tin lưu kho... Microsoft gọi class group để xử l&amp;amp;iacute; c&amp;amp;aacute;c data một c&amp;amp;aacute;ch hiệu quả v&amp;amp;agrave; thống nhất l&amp;amp;agrave; Business Entity. (Mặt kh&amp;amp;aacute;c, class group c&amp;amp;oacute; vai tr&amp;amp;ograve; tương tự trong Community của ph&amp;amp;acirc;n t&amp;amp;iacute;ch/thiết kế hướng đối tượng cũng được gọi l&amp;amp;agrave; Domain Object).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;C&amp;amp;oacute; 2 phương ph&amp;amp;aacute;p tạo Business Entity trong .NET Framework 2.0. Đ&amp;amp;oacute; l&amp;amp;agrave; phương ph&amp;amp;aacute;p sử dụng nguy&amp;amp;ecirc;n DataSet class, v&amp;amp;agrave; phương ph&amp;amp;aacute;p sử dụng Visual Studio 2005 để cho sinh tự động Typed-DataSet. (Phương ph&amp;amp;aacute;p tạo class độc lập trong Java...cũng được xem x&amp;amp;eacute;t, tuy nhi&amp;amp;ecirc;n nếu l&amp;amp;agrave;m như vậy th&amp;amp;igrave; sẽ mất đi &amp;amp;yacute; nghĩa của việc sử dụng .NET Framework 2.0. V&amp;amp;igrave; thế trong t&amp;amp;agrave;i liệu n&amp;amp;agrave;y sẽ bỏ qua phương ph&amp;amp;aacute;p đ&amp;amp;oacute;.)&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Sau đ&amp;amp;acirc;y, ch&amp;amp;uacute;ng t&amp;amp;ocirc;i xin tr&amp;amp;igrave;nh b&amp;amp;agrave;y c&amp;amp;aacute;c vấn đề của phương ph&amp;amp;aacute;p sử dụng nguy&amp;amp;ecirc;n DataSet class, v&amp;amp;agrave; c&amp;amp;aacute;ch Typed-DataSet giải quyết những vấn đề đ&amp;amp;oacute;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Trong t&amp;amp;agrave;i liệu n&amp;amp;agrave;y sẽ sử dụng ER Diagram như dưới để l&amp;amp;agrave;m r&amp;amp;otilde; vấn  đề n&amp;amp;agrave;y.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img src=&amp;quot;http://aptech.ac.vn/blogs/programming/ERD%20Category&amp;amp;amp;Product.png&amp;quot; alt=&amp;quot;ER Diagram&amp;quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;amp;nbsp;&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;C&amp;amp;aacute;c vấn đề của phương ph&amp;amp;aacute;p sử dụng  nguy&amp;amp;ecirc;n DataSet class&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Dưới đ&amp;amp;acirc;y l&amp;amp;agrave; source code cụ thể cho phương ph&amp;amp;aacute;p sử dụng nguy&amp;amp;ecirc;n DataSet class. Nếu compile rồi thực hiện source code dưới, th&amp;amp;igrave; sẽ output ra m&amp;amp;agrave;n h&amp;amp;igrave;nh console những sản phẩm c&amp;amp;oacute; gi&amp;amp;aacute; trị dưới $2000.00.&amp;lt;/p&amp;gt;
&amp;lt;pre title=&amp;quot;code&amp;quot; class=&amp;quot;brush: csharp;&amp;quot;&amp;gt;
//  Tạo DataSet
using  (DataSet ds = new DataSet())
{
    //  Tạo connection.
    using  (SqlConnection sc = new SqlConnection(
        &amp;amp;quot;Data Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated Security=true;&amp;amp;quot;))
    {
        //  Tạo DataAdapter.
        using  (SqlDataAdapter sda = new SqlDataAdapter(&amp;amp;quot;select * from Product where price &amp;amp;lt;= 2000.00&amp;amp;quot;, sc))
        {
            //  Sử dụng DataAdapter, để lấy data của Product Table.
            sda.Fill(ds, &amp;amp;quot;Product&amp;amp;quot;);
        }
    }

    //  X&amp;amp;aacute;c nhận việc lấy dữ liệu đ&amp;amp;uacute;ng.

    //  Tất cả DataRow của Product Table đ&amp;amp;atilde; lấy.
    foreach (DataRow dr in ds.Tables[&amp;amp;quot;Product&amp;amp;quot;].Rows)
    {
        //  Output ra m&amp;amp;agrave;n h&amp;amp;igrave;nh Console
        Console.WriteLine(&amp;amp;quot;{0}\r\n{1}\r\n{2:c}\r\n&amp;amp;quot;, dr[&amp;amp;quot;Name&amp;amp;quot;], dr[&amp;amp;quot;Description&amp;amp;quot;], dr[&amp;amp;quot;Price&amp;amp;quot;]);
    }
}

&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;(Viết ra chỉ nhằm mục đ&amp;amp;iacute;ch tham khảo) using l&amp;amp;agrave; từ d&amp;amp;agrave;nh ri&amp;amp;ecirc;ng để gọi tự động Dispose() method. Việc giải ph&amp;amp;oacute;ng memory trong .NET Framework 2.0 được garbage collection l&amp;amp;agrave;m tự động, tuy nhi&amp;amp;ecirc;n kh&amp;amp;ocirc;ng tự động giải ph&amp;amp;oacute;ng trong trường hợp đ&amp;amp;atilde; sử dụng resource như kết nối th&amp;amp;ocirc;ng tin. Đối với business application c&amp;amp;oacute; y&amp;amp;ecirc;u cầu độ tin cậy, trong trường hợp sử dụng resource ngo&amp;amp;agrave;i bộ nhớ th&amp;amp;igrave; &amp;lt;b&amp;gt;bắt buộc&amp;lt;/b&amp;gt; phải gọi Dispose()method. Đ&amp;amp;acirc;y l&amp;amp;agrave; việc rất phức tạp (để c&amp;amp;oacute; thể gọi được Dispose()method ngay cả khi ph&amp;amp;aacute;t sinh ngoại lệ th&amp;amp;igrave; phải viết try/finally), n&amp;amp;ecirc;n từ kh&amp;amp;oacute;a using được sử dụng.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Nếu chỉ nh&amp;amp;igrave;n qua th&amp;amp;igrave; sẽ thấy source code tr&amp;amp;ecirc;n kh&amp;amp;ocirc;ng c&amp;amp;oacute; vấn đề g&amp;amp;igrave;. Nếu Data Binding tr&amp;amp;ecirc;n GridView của Windows Forms th&amp;amp;igrave; vẫn c&amp;amp;oacute; thể xử l&amp;amp;iacute; data. &amp;lt;b&amp;gt;Nếu chỉ c&amp;amp;oacute;  1 table&amp;lt;/b&amp;gt;, th&amp;amp;igrave; cũng kh&amp;amp;ocirc;ng c&amp;amp;oacute; vấn đề lớn g&amp;amp;igrave; xảy ra cho d&amp;amp;ugrave; &amp;amp;aacute;p dụng  phương ph&amp;amp;aacute;p sử dụng nguy&amp;amp;ecirc;n DataSet.&amp;lt;/p&amp;gt;
&amp;lt;h4&amp;gt;Sẽ thử chia th&amp;amp;agrave;nh 2 table để hiểu r&amp;amp;otilde; vấn đề tr&amp;amp;ecirc;n&amp;lt;/h4&amp;gt;
&amp;lt;p&amp;gt;Phương ph&amp;amp;aacute;p được nghĩ tới đầu ti&amp;amp;ecirc;n trong trường hợp 1 table bị chia th&amp;amp;agrave;nh 2 table l&amp;amp;agrave; phương ph&amp;amp;aacute;p JOIN. C&amp;amp;acirc;u lệnh SELECT trong phần source code tr&amp;amp;ecirc;n đ&amp;amp;atilde; thay đổi như dưới đ&amp;amp;acirc;y.&amp;lt;/p&amp;gt;
&amp;lt;pre title=&amp;quot;code&amp;quot; class=&amp;quot;brush: sql;&amp;quot;&amp;gt;
select
    Product.Name, Product.Description, Product.Price, Category.Name 
from
    Product 
        inner join Category ON Product.CategoryIdentity = Category.[Identity] 
where
    Price &amp;amp;lt;= 2000.00&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;Với c&amp;amp;aacute;ch l&amp;amp;agrave;m n&amp;amp;agrave;y, cho d&amp;amp;ugrave; chia th&amp;amp;agrave;nh nhiều Table cũng kh&amp;amp;ocirc;ng c&amp;amp;oacute; vấn đề g&amp;amp;igrave;. Mặc d&amp;amp;ugrave; gắn điều kiện nếu chỉ hiện thị data l&amp;amp;ecirc;n m&amp;amp;agrave;n h&amp;amp;igrave;nh.Tuy nhi&amp;amp;ecirc;n với phương ph&amp;amp;aacute;p n&amp;amp;agrave;y sẽ rất kh&amp;amp;oacute; khăn trong việc update data.&amp;lt;/p&amp;gt;
&amp;lt;h4&amp;gt;Bằng phương ph&amp;amp;aacute;p JOIN sẽ rất kh&amp;amp;oacute; khăn trong việc update data&amp;lt;/h4&amp;gt;
&amp;lt;p&amp;gt;Lấy kết quả đ&amp;amp;atilde; JOIN v&amp;amp;agrave; hiển thị ra bảng. Nếu trong trường hợp c&amp;amp;acirc;u lệnh SELECT như tr&amp;amp;ecirc;n th&amp;amp;igrave; sẽ hiển thị ra bảng như dưới đ&amp;amp;acirc;y. (Để thu gọn m&amp;amp;agrave;n h&amp;amp;igrave;nh sẽ lược bỏ Product.Description.)&amp;lt;/p&amp;gt;
&amp;lt;table style=&amp;quot;width: 329px; height: 124px;&amp;quot;&amp;gt;
    &amp;lt;tbody&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot;&amp;gt;Product.Name&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot;&amp;gt;Product.Price&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot;&amp;gt;Category.Name&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th align=&amp;quot;left&amp;quot; id=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;ThinkPad  T61&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;$2200.00&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;Lenovo  ThinkPad Series&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;ThinkPad X60S&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;$1200.00&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;Lenovo  ThinkPad Series&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
        &amp;lt;tr&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;VAIO Type U&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;$1500.00&amp;lt;/th&amp;gt;
            &amp;lt;th align=&amp;quot;&amp;quot; style=&amp;quot;font-weight: normal;&amp;quot;&amp;gt;Sony VAIO  Series&amp;lt;/th&amp;gt;
        &amp;lt;/tr&amp;gt;
    &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;
&amp;lt;p&amp;gt;Ch&amp;amp;uacute;ng ta sẽ thử c&amp;amp;ugrave;ng suy nghĩ. Nếu thay Category.Name của d&amp;amp;ograve;ng đầu ti&amp;amp;ecirc;n th&amp;amp;agrave;nh &amp;amp;quot;IBM ThinkPad Series&amp;amp;quot; th&amp;amp;igrave; sẽ như thế n&amp;amp;agrave;o? C&amp;amp;oacute; update Name của Category Table kh&amp;amp;ocirc;ng? Nếu để nguy&amp;amp;ecirc;n l&amp;amp;agrave; &amp;amp;quot;Lenovo ThinkPad Series&amp;amp;quot; th&amp;amp;igrave; d&amp;amp;ograve;ng thứ 2 sẽ kh&amp;amp;ocirc;ng bị chỉnh sửa? Nếu x&amp;amp;oacute;a đi d&amp;amp;ograve;ng thứ 3 th&amp;amp;igrave; category Sony VAIO Series sẽ như thế n&amp;amp;agrave;o?c&amp;amp;oacute; bị x&amp;amp;oacute;a đi kh&amp;amp;ocirc;ng? Th&amp;amp;igrave; c&amp;amp;oacute; lẽ chỉ th&amp;amp;igrave;nh thoảng mới thấy tr&amp;amp;ecirc;n m&amp;amp;agrave;n h&amp;amp;igrave;nh xuất hiện sản phẩm Sony VAIO Series với gi&amp;amp;aacute; &amp;amp;gt;=2000$.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Với l&amp;amp;yacute; do tr&amp;amp;ecirc;n, sẽ kh&amp;amp;ocirc;ng thể sử dụng JOIN trong trường hợp update. Hầu hết trong c&amp;amp;aacute;c business application đều c&amp;amp;oacute; Update Data. V&amp;amp;igrave; thế, trong business application m&amp;amp;agrave; chỉ dựa v&amp;amp;agrave;o JOIN th&amp;amp;igrave; rất nguy hiểm.&amp;lt;/p&amp;gt;
&amp;lt;h4&amp;gt;Thực tế th&amp;amp;igrave; c&amp;amp;oacute; thể đưa nhiều DataTable v&amp;amp;agrave;o DataSet&amp;lt;/h4&amp;gt;
&amp;lt;p&amp;gt;Kĩ thuật vi&amp;amp;ecirc;n Microsoft những người đ&amp;amp;atilde; tạo .NET Framework 2.0 tất nhi&amp;amp;ecirc;n nắm được những điều đ&amp;amp;atilde; tr&amp;amp;igrave;nh b&amp;amp;agrave;y đến đ&amp;amp;acirc;y. V&amp;amp;igrave; vậy tr&amp;amp;ecirc;n thực tế, trong DataSet đ&amp;amp;atilde; chuẩn bị sẵn cấu tr&amp;amp;uacute;c để c&amp;amp;oacute; thể xử l&amp;amp;iacute; nhiều Table một c&amp;amp;aacute;ch tự nhi&amp;amp;ecirc;n. Dưới đ&amp;amp;acirc;y l&amp;amp;agrave; source code cụ thể đ&amp;amp;atilde; sử dụng function đ&amp;amp;oacute;.&amp;lt;/p&amp;gt;
&amp;lt;pre title=&amp;quot;code&amp;quot; class=&amp;quot;brush: csharp;&amp;quot;&amp;gt;
//  Tạo DataSet.
using  (DataSet ds = new DataSet())
{
    //  Tạo Connection.
    using  (SqlConnection sc = new SqlConnection(
        &amp;amp;quot;Data Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated Security=true;&amp;amp;quot;))
    {
        //  Trước ti&amp;amp;ecirc;n, lấy tất cả c&amp;amp;aacute;c Category. 
        using  (SqlDataAdapter sda = new SqlDataAdapter(&amp;amp;quot;select * from Category&amp;amp;quot;, sc))
        {
            sda.Fill(ds, &amp;amp;quot;Category&amp;amp;quot;);
        }

        //  Lấy tất cả c&amp;amp;aacute;c sản phẩm c&amp;amp;oacute; gi&amp;amp;aacute; trị &amp;amp;lt;= $2000.
        using  (SqlDataAdapter sda = new SqlDataAdapter(&amp;amp;quot;select * from Product where Price &amp;amp;lt;= 2000.00&amp;amp;quot;, sc))
        {
            sda.Fill(ds, &amp;amp;quot;Product&amp;amp;quot;);
        }
    }

    //  Add th&amp;amp;ecirc;m DataRelation li&amp;amp;ecirc;n kết category với product.
    ds.Relations.Add(new DataRelation(&amp;amp;quot;Category_Product&amp;amp;quot;, 
        ds.Tables[&amp;amp;quot;Category&amp;amp;quot;].Columns[&amp;amp;quot;Identity&amp;amp;quot;], ds.Tables[&amp;amp;quot;Product&amp;amp;quot;].Columns[&amp;amp;quot;CategoryIdentity&amp;amp;quot;]));

    //  Đến đ&amp;amp;acirc;y, c&amp;amp;oacute; thể lấy được Product Group thuộc v&amp;amp;agrave;o Category bằng DataRow GetChildRows(&amp;amp;quot;Category_Product&amp;amp;quot;) của DataRow của Category, 
    //  v&amp;amp;agrave; c&amp;amp;oacute; thể lấy được category c&amp;amp;oacute; chứa product bằng GetParentRow(&amp;amp;quot;Category_Product&amp;amp;quot;) của DataRow của product.

    //  X&amp;amp;aacute;c nhận xem lấy dữ liệu c&amp;amp;oacute; đ&amp;amp;uacute;ng kh&amp;amp;ocirc;ng.

    //  Tất cả DataRow của product table đ&amp;amp;atilde; lấy.
    foreach (DataRow dr in ds.Tables[&amp;amp;quot;Product&amp;amp;quot;].Rows)
    {
        //  Output ra m&amp;amp;agrave;n h&amp;amp;igrave;nh Console.
        Console.WriteLine(&amp;amp;quot;{0}\r\n{1}\r\n{2:c}\r\n{3}\r\n&amp;amp;quot;, 
            dr[&amp;amp;quot;Name&amp;amp;quot;], dr[&amp;amp;quot;Description&amp;amp;quot;], dr[&amp;amp;quot;Price&amp;amp;quot;], dr.GetParentRow(&amp;amp;quot;Category_Product&amp;amp;quot;)[&amp;amp;quot;Name&amp;amp;quot;]);

        //  V&amp;amp;igrave; c&amp;amp;oacute; thể lấy được DataRow của category bằng GetParentRow(&amp;amp;quot;Category_Product&amp;amp;quot;)
        //  cho n&amp;amp;ecirc;n c&amp;amp;oacute; thể hiển thị category name nếu l&amp;amp;agrave; dr.GetParentRow(&amp;amp;quot;Category_Product&amp;amp;quot;)[&amp;amp;quot;Name&amp;amp;quot;].
    }
}&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;Point ch&amp;amp;iacute;nh l&amp;amp;agrave; việc gọi ra Add()method đối với Relations Property của DataSet. Nếu với c&amp;amp;aacute;ch viết source code như tr&amp;amp;ecirc;n th&amp;amp;igrave; sẽ kh&amp;amp;ocirc;ng ph&amp;amp;aacute;t sinh c&amp;amp;aacute;c vấn đề giống như trong trường hợp JOIN. Tuy nhi&amp;amp;ecirc;n l&amp;amp;agrave; do chỉ c&amp;amp;oacute; 1 d&amp;amp;ograve;ng Category giống như tr&amp;amp;ecirc;n RDBMS. (Trong source code tr&amp;amp;ecirc;n c&amp;amp;oacute; vấn đề l&amp;amp;agrave; sẽ lấy tất cả, kể cả những Category kh&amp;amp;ocirc;ng cần thiết. Về vấn đề n&amp;amp;agrave;y sẽ giải quyết bằng &amp;amp;quot;C&amp;amp;aacute;ch tạo Data Access Logic Component&amp;amp;quot; sẽ m&amp;amp;ocirc; tả ở phần sau.)&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Với l&amp;amp;iacute; do tr&amp;amp;ecirc;n, nếu l&amp;amp;agrave;m DatSet một c&amp;amp;aacute;ch cẩn thận v&amp;amp;agrave; sử dụng th&amp;amp;igrave;  chắc l&amp;amp;agrave; sẽ được. Chắc chắn sẽ được, nếu như ch&amp;amp;uacute;ng ta lập tr&amp;amp;igrave;nh &amp;lt;b&amp;gt;kh&amp;amp;ocirc;ng  phải l&amp;amp;agrave; c&amp;amp;ocirc;ng việc m&amp;amp;agrave; chỉ l&amp;amp;agrave; sở th&amp;amp;iacute;ch&amp;lt;/b&amp;gt;.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Tuy nhi&amp;amp;ecirc;n th&amp;amp;igrave; phương ph&amp;amp;aacute;p sử dụng DataSet v&amp;amp;agrave; DataRelation l&amp;amp;agrave; phương ph&amp;amp;aacute;p rất phiền to&amp;amp;aacute;i. Trước hết, mỗi lần lấy data từ RDBMS th&amp;amp;igrave; việc add th&amp;amp;ecirc;m DataRelation rất phiền to&amp;amp;aacute;i. Hơn nữa th&amp;amp;igrave; cho đến đ&amp;amp;acirc;y, ch&amp;amp;uacute;ng t&amp;amp;ocirc;i cũng đ&amp;amp;atilde; bỏ qua vấn đề n&amp;amp;agrave;y, tuy nhi&amp;amp;ecirc;n th&amp;amp;igrave; việc viết kiểu như dataRow[&amp;amp;quot;&amp;lt;i&amp;gt;ColumnName&amp;lt;/i&amp;gt;&amp;amp;quot;] cũng  rất phiền. Việc kh&amp;amp;ocirc;ng đ&amp;amp;aacute;ng kể g&amp;amp;igrave; như thế n&amp;amp;agrave;y cũng trở th&amp;amp;agrave;nh vấn đề l&amp;amp;agrave; bởi v&amp;amp;igrave; business application rất phức tạp đến mức kh&amp;amp;ocirc;ng thể sử dụng GridView control , hiển thị l&amp;amp;ecirc;n m&amp;amp;agrave;n h&amp;amp;igrave;nh v&amp;amp;agrave; được người sử dụng input v&amp;amp;agrave;o. V&amp;amp;iacute; dụ như việc kiểm tra gi&amp;amp;aacute; trị input, t&amp;amp;iacute;nh to&amp;amp;aacute;n chi ph&amp;amp;iacute; gửi, lựa chọn c&amp;amp;aacute;c sản phẩm được giới thiệu. Nếu muốn tạo một site về electric commerce giống như amazon.com th&amp;amp;igrave; buộc ch&amp;amp;uacute;ng ta phải viết source code để thực hiện những business logic phức tạp như thế n&amp;amp;agrave;y. Giả sử trong phần source code đ&amp;amp;oacute; c&amp;amp;oacute; viết dataRow[&amp;amp;quot;&amp;lt;i&amp;gt;ColumnName&amp;lt;/i&amp;gt;&amp;amp;quot;], th&amp;amp;igrave; sẽ tốn chi ph&amp;amp;iacute; cho việc input do kh&amp;amp;ocirc;ng thể sử dụng IntelliSense trong string, v&amp;amp;agrave; sẽ tốn chi ph&amp;amp;iacute; cho việc test do kh&amp;amp;ocirc;ng biết được l&amp;amp;agrave; column name đến khi thực hiện thử c&amp;amp;oacute; đ&amp;amp;uacute;ng kh&amp;amp;ocirc;ng?&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Vậy th&amp;amp;igrave; n&amp;amp;ecirc;n l&amp;amp;agrave;m thế n&amp;amp;agrave;o? V&amp;amp;acirc;ng, h&amp;amp;atilde;y sử dụng Typed-DataSet m&amp;amp;agrave; USOL  Việt Nam đề xuất.&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;Nếu l&amp;amp;agrave; Typed-DataSet th&amp;amp;igrave; c&amp;amp;oacute; thể giải quyết một c&amp;amp;aacute;ch th&amp;amp;ocirc;ng minh cả những vấn đề như nhiều table hay cả những vấn đề li&amp;amp;ecirc;n quan đến việc update.&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Để hiểu được Typed-DataSet th&amp;amp;igrave; điều quan trọng số 1 l&amp;amp;agrave; d&amp;amp;ugrave;ng thử n&amp;amp;oacute;. H&amp;amp;atilde;y khởi động Visual Studio 2005, tạo project th&amp;amp;iacute;ch hợp, rightclick v&amp;amp;agrave;o project m&amp;amp;agrave; đ&amp;amp;atilde; tạo bằng [Solution Explorer], lựa chọn [Add] - [New Item...] từ pop up menu, lựa chọn [DataSet] icon tại hộp thoại [Add New Item] v&amp;amp;agrave; click v&amp;amp;agrave;o n&amp;amp;uacute;t [OK]. Khi đ&amp;amp;oacute; th&amp;amp;igrave; Typed-DataSet được tạo. Sau khi Typed-DataSet được tạo, h&amp;amp;atilde;y draft and drop table th&amp;amp;iacute;ch hợp từ [Server Explorer] như sơ đồ dưới đ&amp;amp;acirc;y.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img width=&amp;quot;553&amp;quot; height=&amp;quot;213&amp;quot; src=&amp;quot;http://dev.meotom.net/Uploads/admin/2010/3/24/Tyd-DataSet%20DD.png&amp;quot; alt=&amp;quot;draft and drop table v&amp;amp;agrave;o Typed-DataSet&amp;quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Đến đ&amp;amp;acirc;y, th&amp;amp;igrave; việc tạo Typed-DataSet đ&amp;amp;atilde; ho&amp;amp;agrave;n th&amp;amp;agrave;nh. Với những thao t&amp;amp;aacute;c cho đến đ&amp;amp;acirc;y th&amp;amp;igrave; ch&amp;amp;uacute;ng ta c&amp;amp;oacute; thể giải quyết kể cả vấn đề add th&amp;amp;ecirc;m DataRelation m&amp;amp;agrave; trước đ&amp;amp;acirc;y cảm thấy rất phiền to&amp;amp;aacute;i, v&amp;amp;agrave; cả vấn đề bắt buộc phải viết l&amp;amp;agrave; dataRow[&amp;amp;quot;&amp;lt;i&amp;gt;ColumnName&amp;lt;/i&amp;gt;&amp;amp;quot;].Với những căn cứ như vậy th&amp;amp;igrave; ch&amp;amp;uacute;ng ta h&amp;amp;atilde;y d&amp;amp;ugrave;ng Typed-DataSet v&amp;amp;agrave; thử viết lại source code tr&amp;amp;ecirc;n. Dưới đ&amp;amp;acirc;y l&amp;amp;agrave; source code đ&amp;amp;atilde; viết lại.&amp;lt;/p&amp;gt;
&amp;lt;pre title=&amp;quot;code&amp;quot; class=&amp;quot;brush: csharp;&amp;quot;&amp;gt;
//  Tạo Typed-DataSet.
using  (CatalogDataSet ds = new CatalogDataSet())
{
    //  Về phần lấy data th&amp;amp;igrave; giống với trường hợp sử dụng nguy&amp;amp;ecirc;n DataSet.
    using  (SqlConnection sc = new SqlConnection(
        &amp;amp;quot;Data Source=localhost\\SQLExpress; Initial Catalog=UsolV; Integrated Security=true;&amp;amp;quot;))
    {
        using  (SqlDataAdapter sda = new SqlDataAdapter(&amp;amp;quot;select * from Category&amp;amp;quot;, sc))
        {
            sda.Fill(ds, &amp;amp;quot;Category&amp;amp;quot;);
        }

        using  (SqlDataAdapter sda = new SqlDataAdapter(&amp;amp;quot;select * from Product where Price &amp;amp;lt;= 2000.00&amp;amp;quot;, sc))
        {
            sda.Fill(ds, &amp;amp;quot;Product&amp;amp;quot;);
        }
    }

    //  Kh&amp;amp;ocirc;ng cần add th&amp;amp;ecirc;m DataRelation.

    //  Đ&amp;amp;atilde; ho&amp;amp;agrave;n th&amp;amp;agrave;nh định nghĩa kiểu cho d&amp;amp;ograve;ng của sản phẩm, hơn nữa cũng c&amp;amp;oacute; thể lấy được DataTable bằng property của t&amp;amp;ecirc;n giống với t&amp;amp;ecirc;n table. 
    foreach (CatalogDataSet.ProductRow dr in ds.Product)
    {
        //  C&amp;amp;oacute; thể lấy được Data bằng property của t&amp;amp;ecirc;n giống với t&amp;amp;ecirc;n colum. 
        //  Ngo&amp;amp;agrave;i ra cũng c&amp;amp;oacute; thể lấy được category trực thuộc trong CategoryRow.
        Console.WriteLine(&amp;amp;quot;{0}\r\n{1}\r\n{2:c}\r\n{3}\r\n&amp;amp;quot;,  
            dr.Name, dr.Description, dr.Price, dr.CategoryRow.Name);
      
        //  Ở đ&amp;amp;acirc;y ch&amp;amp;uacute;ng t&amp;amp;ocirc;i kh&amp;amp;ocirc;ng tr&amp;amp;igrave;nh b&amp;amp;agrave;y, 
        //  nhưng c&amp;amp;oacute; thể lấy được product group thuộc category bằng GetProductRows() của CategoryDataRow.
    }
}&amp;lt;/pre&amp;gt;
&amp;lt;p&amp;gt;Nếu nh&amp;amp;igrave;n v&amp;amp;agrave;o source code tr&amp;amp;ecirc;n th&amp;amp;igrave; t&amp;amp;ocirc;i nghĩ l&amp;amp;agrave; mọi người c&amp;amp;oacute; thể hiểu phần sau hết sức đơn giản. (c&amp;amp;ograve;n phần ph&amp;amp;iacute;a trước cũng sẽ đơn giản nếu c&amp;amp;oacute; thể sử dụng TableAdapter tr&amp;amp;igrave;nh b&amp;amp;agrave;y bằng 「phương ph&amp;amp;aacute;p tạo Data Access Logic Component」). Khi đ&amp;amp;oacute; sẽ kh&amp;amp;ocirc;ng cần add th&amp;amp;ecirc;m DataRelation, v&amp;amp;agrave; n&amp;amp;ecirc;n viết dataRow.Name hơn l&amp;amp;agrave; dataRow[&amp;amp;quot;Name&amp;amp;quot;], v&amp;amp;agrave; n&amp;amp;ecirc;n viết l&amp;amp;agrave; dataRow.CategoryRow.Name hơn l&amp;amp;agrave; viết dataRow.GetParentRow(&amp;amp;quot;Category_Product&amp;amp;quot;)[&amp;amp;quot;Name&amp;amp;quot;] th&amp;amp;igrave; sẽ đơn giản hơn rất nhiều phải kh&amp;amp;ocirc;ng? V&amp;amp;igrave; c&amp;amp;oacute; thể sử dụng được IntelliSense, hơn nữa d&amp;amp;ugrave; t&amp;amp;ecirc;n cột bị sai đi nữa chỉ cần compile l&amp;amp;agrave; c&amp;amp;oacute; thể hiểu được.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Cơ chế (mechanism) của Typed-DataSet c&amp;amp;oacute; trong việc Visual Studio 2005 tự sinh source code . Bạn h&amp;amp;atilde;y thử click v&amp;amp;agrave;o [+] ở b&amp;amp;ecirc;n tr&amp;amp;aacute;i của Typed-DataSet trong [Solution Explorer] của Visual Studio 2005. Khi đ&amp;amp;oacute;, chắc chắn sẽ hiện ra file &amp;amp;quot;&amp;lt;i&amp;gt;Typed-DataSet name&amp;lt;/i&amp;gt;.Designer.cs&amp;amp;quot; như  h&amp;amp;igrave;nh dưới đ&amp;amp;acirc;y.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img width=&amp;quot;257&amp;quot; height=&amp;quot;297&amp;quot; src=&amp;quot;http://dev.meotom.net/Uploads/admin/2010/3/24/Typed-DataSet_Designer.png&amp;quot; alt=&amp;quot;Typed-DataSet.Designer.cs&amp;quot; /&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Ch&amp;amp;iacute;nh  &amp;amp;quot;&amp;lt;i&amp;gt;Typed-DataSet name&amp;lt;/i&amp;gt;.Designer.cs&amp;amp;quot; nn&amp;amp;agrave;y l&amp;amp;agrave; phần source code m&amp;amp;agrave; Visual Studio 2005 tự sinh. Nếu thử loại đi phần b&amp;amp;ecirc;n trong th&amp;amp;igrave; source code c&amp;amp;oacute; add th&amp;amp;ecirc;m DataRelation v&amp;amp;agrave; source code access v&amp;amp;agrave;o DataRow[&amp;amp;quot;Name&amp;amp;quot;] trong property name sẽ được m&amp;amp;ocirc; tả. V&amp;amp;igrave; Visual Studio 2005 l&amp;amp;agrave;m cho ch&amp;amp;uacute;ng ta tất cả những phần c&amp;amp;oacute; thể l&amp;amp;agrave;m một c&amp;amp;aacute;ch m&amp;amp;aacute;y m&amp;amp;oacute;c, v&amp;amp;igrave; vậy ch&amp;amp;uacute;ng ta chỉ tập trung v&amp;amp;agrave;o những phần c&amp;amp;oacute; t&amp;amp;iacute;nh chất s&amp;amp;aacute;ng tạo, những phần thực hiện business logic tr&amp;amp;ecirc;n source code.&amp;lt;/p&amp;gt;
&amp;lt;h3&amp;gt;T&amp;amp;oacute;m tắt&amp;lt;/h3&amp;gt;
&amp;lt;p&amp;gt;Business application rất phức tạp. Phức tạp ở ngay cả việc phải sử dụng nhiều table. V&amp;amp;igrave; thế n&amp;amp;ecirc;n sẽ biding data c&amp;amp;aacute;c DataTable c&amp;amp;oacute; DataSet trong GridView control, hiển thị l&amp;amp;ecirc;n m&amp;amp;agrave;n h&amp;amp;igrave;nh dưới dạng bảng, kh&amp;amp;ocirc;ng thể thực hiện được nếu chỉ bằng phương ph&amp;amp;aacute;p đơn giản như cho input/output. (Nếu như chỉ maintain 1 table th&amp;amp;igrave; l&amp;amp;agrave;m bằng Microsoft Access sẽ nhanh v&amp;amp;agrave; rẻ hơn nhiều so với l&amp;amp;agrave;m chương tr&amp;amp;igrave;nh bằng c&amp;amp;aacute;c Visual Studio 2005).&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Bằng việc sử dụng JOIN trong c&amp;amp;acirc;u lệnh SELECT, để l&amp;amp;agrave;m th&amp;amp;agrave;nh 1 bảng, c&amp;amp;oacute; thể giả coi như l&amp;amp;agrave; chỉ c&amp;amp;oacute; 1 bảng. Tuy nhi&amp;amp;ecirc;n trong business application th&amp;amp;igrave; update l&amp;amp;agrave; chức năng đi k&amp;amp;egrave;m, nếu thử JOIN một lần th&amp;amp;igrave; sẽ kh&amp;amp;ocirc;ng thể update được, v&amp;amp;igrave; thế kh&amp;amp;ocirc;ng thể sử dụng được phương ph&amp;amp;aacute;p n&amp;amp;agrave;y cho business application.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Cũng c&amp;amp;oacute; thể ph&amp;amp;ograve;ng tr&amp;amp;aacute;nh bằng việc l&amp;amp;agrave;m cẩn thận c&amp;amp;aacute;ch sử dụng Data Set. V&amp;amp;igrave; c&amp;amp;oacute; thể cho nhiều DataTable v&amp;amp;agrave;o trong DataSet, hơn nữa c&amp;amp;ograve;n c&amp;amp;oacute; thể thiết lập mối quan hệ giữa DataTable đ&amp;amp;oacute; bằng DataRelation. Với phương ph&amp;amp;aacute;p n&amp;amp;agrave;y, th&amp;amp;igrave; data m&amp;amp;agrave; DataSet đang hiển thị sẽ c&amp;amp;oacute; cấu tr&amp;amp;uacute;c giống với data của RDBMS, v&amp;amp;igrave; thế đương nhi&amp;amp;ecirc;n c&amp;amp;oacute; thể xử l&amp;amp;iacute; nhiều table, v&amp;amp;agrave; update cũng đơn giản. Thế nhưng v&amp;amp;igrave; buộc phải nhập bằng tay table name, column name, relationship name cho n&amp;amp;ecirc;n vẫn chưa thỏa m&amp;amp;atilde;n về chi ph&amp;amp;iacute; thực hiện v&amp;amp;agrave; chi ph&amp;amp;iacute; test.&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Tất cả những vấn đề m&amp;amp;agrave; ch&amp;amp;uacute;ng t&amp;amp;ocirc;i tr&amp;amp;igrave;nh b&amp;amp;agrave;y cho tới đ&amp;amp;acirc;y th&amp;amp;igrave; đều c&amp;amp;oacute; thể giải quyết được bằng việc sử dụng Typed-DataSet. Typed-DataSet l&amp;amp;agrave; phương thức m&amp;amp;agrave; Visual Studio 2005 tự sinh ra những property để lấy table, colum, relationship bằng những thao t&amp;amp;aacute;c đơn giản như draft and drop table từ [Server Explorer]. Nếu như d&amp;amp;ugrave;ng phương ph&amp;amp;aacute;p Typed-DataSet, th&amp;amp;igrave; với chi ph&amp;amp;iacute; thấp nhất cũng c&amp;amp;oacute; thể thực hiện phương ph&amp;amp;aacute;p sử dụng tối ưu những t&amp;amp;iacute;nh năng của DataSet. Trong trường hợp muốn tạo business application nhất định h&amp;amp;atilde;y thử sử dụng Typed-DataSet n&amp;amp;agrave;y.&amp;lt;/p&amp;gt;
&amp;lt;p style=&amp;quot;text-align: right;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-weight: bold;&amp;quot;&amp;gt;Theo [Usol VN] &amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;</Body><CommentEnabled>True</CommentEnabled><ViewCount>0</ViewCount><ReleaseDate>3/28/2010 7:15:02 AM</ReleaseDate><TotalComment>0</TotalComment><IsMedia>False</IsMedia><IsPicture>False</IsPicture><IsVote>True</IsVote><ArticlePassword /><PostVisible>0</PostVisible><ArticlePath>/2010/3/24/ADO-NET-2-0-phan-1-35E</ArticlePath><Approved>True</Approved><ImagePath /><CategoryId>26</CategoryId><ArrayCatID>26|25</ArrayCatID></Article></Articles>